package edu.gatech.oad.mule;

import java.awt.Color;
import java.awt.Point;
import java.io.Serializable;

import edu.gatech.oad.mule.config.PlayerData;
import edu.gatech.oad.mule.config.interfaces._ConfigurationPanel;
import edu.gatech.oad.mule.input.interfaces.ControllerOwner;
import edu.gatech.oad.mule.view.interfaces.RenderablePlayer;

/**
 * This class represents a Player in the game. Players are the object the
 * players of the game get to control during the course of the game.
 * 
 * @author Brendan McGarry, Dale Avery, D'Miria Collins, Natasha Parekh, Jaemin
 *         Park
 * @version %I%, %G%
 */
public class Player implements ControllerOwner, RenderablePlayer, Serializable {

	private static final long serialVersionUID = -5155635292073062136L;

	private int playerNum;

	private Color color;

	private MULE mule;

	private Point location;

	private String inputDevice;
	private String name;
	private String race;

	private Wallet wallet;

	private int numOwnedTiles;

	//TODO delete this after JUnit test cases
	public Player(){
		name = "Test Player";
		wallet = new Wallet(0, 0, 0, 1000, 0);
	}//end constructor
	
	/**
	 * This constructor configures a new Player object
	 */
	public Player(int playerNum, _ConfigurationPanel panel) {
		System.out.println("player");
		//grabs the player's config data
		PlayerData data = panel.getPlayerData(playerNum);
		//set up name, race, color, and input device
		name = data.getName();
		race = data.getRace();
		color = data.getColor();
		inputDevice = data.getInputDevice();
		//no MULE in inventory yet
		mule = null;
		//set up the player's wallet
		wallet = new Wallet(panel, race);
		//start the player in the center of the map
		location = new Point(WorldMap.WIDTH / 2, WorldMap.HEIGHT / 2);
		//doesn't own any tiles yet
		numOwnedTiles = 0;
		System.out.println("/player");
	}// end constructor

	/**
	 * @param amount
	 *            The amount of crystite to add to the player's wallet. Can be
	 *            negative, zero, or positive value.
	 */
	public void addCrystite(int amount) {
		wallet.addCrystite(amount);
	}// end method addCrystite

	/**
	 * @param amount
	 *            The amount of energy to add to the player's wallet. Can be
	 *            negative, zero, or positive value.
	 */
	public void addEnergy(int amount) {
		wallet.addEnergy(amount);
	}// end method addEnergy

	/**
	 * @param amount
	 *            The amount of food to add to the player's wallet. Can be
	 *            negative, zero, or positive value.
	 */
	public void addFood(int amount) {
		wallet.addFood(amount);
	}// end method addFood

	/**
	 * @param amount
	 *            The amount of money to add to the player's wallet. Can be
	 *            negative, zero, or positive value.
	 */
	public void addMoney(int amount) {
		wallet.addMoney(amount);
	}// end method addMoney

	/**
	 * @param amount
	 *            The amount of smithore to add to the player's wallet. Can be
	 *            negative, zero, or positive value.
	 */
	public void addSmithore(int amount) {
		wallet.addSmithore(amount);
	}// end method addSmithore

	/**
	 * @return This player's score
	 */
	public int calcScore(){
		return (wallet.getFood() + wallet.getEnergy() + wallet.getSmithore() + 
				wallet.getCrystite() + wallet.getMoney() + 
				(numOwnedTiles * Tile.DEFAULT_COST));
	}//end method calcScore

	/**
	 * overwritten from Object; since player's must have unique names, we can
	 * tell if two players are the same player if they have the same name
	 */
	public boolean equals(Player p) {
		if (p != null) {
			return (name.equals(p.getName()));
		}// end if
		return false;
	}// end method equals

	/**
	 * @return The MULE (if any) the player has in his/her inventory
	 */
	public MULE getMULE() {
		return mule;
	}// end method getMULE

	/**
	 * @return The name of this player
	 */
	public String getName() {
		return name;
	}// end method getName

	/**
	 * @return The number of tiles the player owns
	 */
	public int getNumOwnedTiles(){
		return numOwnedTiles;
	}//end getNumOwnedTiles
	
	/**
	 * This method increments the counter for how
	 * many tiles the player owns
	 */
	public void addTile() {
		numOwnedTiles++;
	}//end method addTile

	/**
	 * @return The player's wallet
	 */
	public Wallet getWallet() {
		return wallet;
	}// end method getWallet

	/**
	 * @return the X coordinate of the player
	 */
	public int getX() {
		return ((int) (location.getX()));
	}// end method getX

	/**
	 * @return the Y coordinate of the player
	 */
	public int getY() {
		return ((int) (location.getY()));
	}// end method getY

	/**
	 * @return Whether or not the player has an outfitted MULE
	 */
	public boolean hasOutfittedMULE() {
		boolean hasOutfittedMULE = false;
		if (mule != null && mule.isOutfitted()) {
			hasOutfittedMULE = true;
		}// end if
		return hasOutfittedMULE;
	}// end method hasOutfittedMULE

	/**
	 * @return This player's input device
	 */
	private String inputDevice() {
		return inputDevice;
	}// end method inputDevice

	/**
	 * Moves the Player at the current location (x,y), by dx along the x axis
	 * and dy along the y axis so that he/she is now at the point (x+dx,y+dy)
	 * 
	 * @param dx
	 *            The amount to translate along the x axis
	 * @param dy
	 *            The amount to translate along the y axis
	 */
	public void move(int dx, int dy) {
		location.translate(dx, dy);
	}//end method move

	/**
	 * Gives the player a new MULE
	 * 
	 * @param mule
	 *            The new mule
	 */
	public void setMULE(MULE mule) {
		this.mule = mule;
	}// end method setMULE

	/**
	 * Changes the Player's location
	 * 
	 * @param x
	 *            The new x-coordinate
	 * @param y
	 *            The new y-coordinate
	 */
	public void setLocation(int x, int y) {
		location.setLocation(x, y);
	}// end method setLocation

	/**
	 * Changes the Player's location
	 * 
	 * @param location
	 *            The new location of the player
	 */
	public void setLocation(Point location) {
		this.location = location;
	}// end method setLocation

	/**
	 * Builds a String representation of the Player.
	 * 
	 * @return a String containing character information
	 */
	public String toString() {
		/*
		String out = "----------\nPlayer " + playerNum + ":\nName: " + name
				+ "\nRace: " + race + "\nColor: " + color.toString()
				+ "\nInput Device: " + inputDevice + "\nWallet"
				+ wallet.toString() + "\n----------";
		return out;*/
		return name;
	}//end method toString

	//==============================
	//	ControllerOwner
	//==============================	

	@Override
	public boolean isSameOwner(Object other) {
		if (other == null)
			return false;

		// other must be a Player
		if (!(other instanceof Player))
			return false;

		// If it is, we can check its name.
		Player test = (Player) other;
		if (!this.name.equals(test.name))
			return false;

		// By this point, we can say that this is the same ControllerOwner as
		// other.
		return true;
	}//end method isSameOwner

	@Override
	public InputDevice getInputDevice() {
		if (inputDevice.equals("Keyboard")) {
			return InputDevice.KEYBOARD_STD;
		}//end if
		else {
			return null;
		}//end else
	}//end method getInputDevice

	//==============================
	//	RenderablePlayer
	//==============================
	
	@Override
	public Point getLocation() {
		return location;
	}// end method getLocation

	@Override
	public Color getColor() {
		return color;
	}// end method getColor
	
	@Override
	public int getCrystite(){
		return wallet.getCrystite();
	}//end method getCrystite

	@Override
	public int getEnergy(){
		return wallet.getEnergy();
	}//end method getEnergy

	@Override
	public int getFood(){
		return wallet.getFood();
	}//end method getFood

	@Override
	public int getMoney(){
		return wallet.getMoney();
	}//end method getMoney

	@Override
	public PlayerRace getRace(){
		if(race.equals("Human")){
			return PlayerRace.HUMAN;
		}//end if
		else if(race.equals("Flapper")){
			return PlayerRace.FLAPPER;
		}//end else if
		else if(race.equals("Bonzoid")){
			return PlayerRace.BONZOID;
		}//end else if
		else if(race.equals("Ugaite")){
			return PlayerRace.UGAITE;
		}//end else if
		else if(race.equals("Buzzite")){
			return PlayerRace.BUZZITE;
		}//end else if
		return PlayerRace.ERROR;
	}//end method getRace
	
	@Override
	public int getSmithore(){
		return wallet.getSmithore();
	}//end method getSmithore

	@Override
	public boolean hasMule(){
		if(mule == null){
			return false;
		}//end if
		else{
			return true;
		}//end else
	}//end method hasMule

}// end class Player
